<!DOCTYPE html>
<html lang="en">

  <head>
    <meta charset="UTF-8" />
    <meta name="viewport"
          content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      body {
        background-color: #1e1e1e;
      }

      @keyframes ColorChange {
        0% {
          outline: 1px solid lightgreen;
        }

        50% {
          outline: 1px solid green;
        }

        1000% {
          outline: 1px solid lightgreen;
        }
      }

      svg {
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate3d(-50%, -50%, 0);
        outline: 1px solid red;
        animation: ColorChange 500ms ease infinite;
      }

      line,
      polyline,
      rect {
        stroke-linecap: round;
        stroke-linejoin: round;
      }
    </style>
  </head>

  <body>
    <svg width="600"
         height="600"
         xmlns="http://www.w3.org/2000/svg"
         xmlns:xlink="http://www.w3.org/1999/xlink"
         preserveAspectRatio="xMinYMin meet"
         stroke-linecap="round"
         stroke-linejoin="round"
         viewBox="0 0 600 600">

      <!-- 第十一章 滤镜、投影 -->

      <!-- 光照效果 -->
      <defs>
        <!-- 曲线 -->
        <path id="curve"
              d="M 0 0 Q 5 20 10 10 T 20 20"
              ➊
              style="stroke: black; fill: none;" />
        <filter id="diff-light"
                color-interpolation-filters="sRGB"
                x="0"
                y="0"
                width="100%"
                height="100%"> ➋
          <!-- 使用curve平铺镜面区域 -->
          <feImage xlink:href="#curve"
                   result="tile"
                   width="20"
                   height="20" /> ➌
          <feTile in="tile"
                  result="tile" />
          <feDiffuseLighting in="tile"
                             ➍
                             lighting-color="#ffffff"
                             surfaceScale="2"
                             ➎
                             diffuseConstant="1"
                             ➏
                             result="diffuseOutput"> ➐
            <fePointLight x="0"
                          y="50"
                          z="50" /> ➑
          </feDiffuseLighting> ➒
          <feComposite in="diffuseOutput"
                       in2="SourceGraphic"
                       operator="in"
                       result="diffuseOutput" /> ➓
          <feBlend in="diffuseOutput"
                   in2="SourceGraphic"
                   mode="screen" />
        </filter>
      </defs>
      <circle id="green-light"
              cx="50"
              cy="50"
              r="50"
              style="fill: #aaa; filter: url(#diff-light)" />
      <!--
        ➊ 定义用作图案的曲线。
        ➋ 设置颜色插值方法和滤镜边界。
        ➌ 用 curve 图像平铺滤镜区域。这会变成凹凸贴图。
        ➍ 这个平铺区域会输入到 <feDiffuseLighting> 元素中，还给它加了一个浅黄色的光照，正如 lighting-color 属性中所指定的。
        ➎ surfaceScale 属性代表阿尔法值为 1 时表面的高度（更通用的说法是，它是计算阿尔法值时的乘积因子）。
        ➏ diffuseConstant 是一个用于确定像素最终 RGB 值的乘积因子。它的值必须大于或等于0，默认值为 1。要让 lighting-color 更明亮，这个值就应该更小（除非我们想要图片褪色）。
        ➐ 这个滤镜的结果将被命名为 diffuseOutput。
        ➑ 这个例子用了一个点光源，意味着光源的光会辐射到所有方向。而我们希望它照亮在滤镜区域的左上角，并且在屏幕的 50 单位前。设置光源离对象越远，对象被照亮得越均匀。在这个例子中，光线距离越近，获得的效果越明显。
        ➒ <feDiffuseLighting> 元素结束。
        ➓ 用 <feComposite> 的 in 属性裁剪滤镜的输出到源图形（圆）的边界。最后，<feBlend> 设置为 screen 模式，它会尝试让源图形变亮，这是滤镜的最后部分。在想要的对象上启用滤镜，生成图
      -->


      <!-- 镜面反射照明 -->

      <defs>
        <path id="curve"
              d="M 0 0 Q 5 20 10 10 T 20 20"
              style="stroke: black; fill: none;" /> ➊
        <filter id="spec-light"
                color-interpolation-filters="sRGB"
                x="0"
                y="0"
                width="100%"
                height="100%"> ➋
          <feImage xlink:href="#curve"
                   result="tile"
                   width="20"
                   height="20" /> ➌
          <feTile in="tile"
                  result="tile" />
          <feSpecularLighting in="tile"
                              ➍
                              lighting-color="#ffffcc"
                              surfaceScale="1"
                              ➎
                              specularConstant="1"
                              ➏
                              specularExponent="4"
                              ➐
                              result="specularOutput"> ➑
            <feDistantLight elevation="20"
                            azimuth="0" /> ➒
          </feSpecularLighting> ➓
          <feComposite in="specularOutput"
                       in2="SourceGraphic"
                       operator="in"
                       result="specularOutput" />
          <feComposite in="specularOutput"
                       in2="SourceGraphic"
                       operator="arithmetic"
                       k1="0"
                       k2="1"
                       k3="1"
                       k4="0" />
        </filter>
      </defs>
      <circle id="green-light"
              cx="150"
              cy="50"
              r="50"
              style="fill: #060; filter: url(#spec-light)" />
      <!--
        ➊ 和前面的例子一样，定义曲线。
        ➋ 与前一个例子的唯一区别是滤镜名称。
        ➌ 和前面的例子一样，这部分平铺曲线。
        ➍ 开始定义 <feSpecularLighting> 滤镜，指定 lighting-color 为淡黄色。
        ➎ surfaceScale 属性代表阿尔法值为 1 时表面的高度（更通用的说法是，它是计算阿尔法值时的乘积因子）。
        ➏ specularConstant 是一个用于确定像素最终 RGB 值的乘积因子。它的值必须大于或等于 0，默认值为 1。要让 lighting-color 更明亮，这个值就应该更小。这个数字的效果也可以通过 specularExponent 属性来缓和。
        ➐ specularExponent 是用来确定像素最终 RGB 值的另一个因子。这个属性的值必须是 0到 128 之间的数字，默认值是 1。数字越大，结果越“明亮”。
        ➑ 这个滤镜的结果将被命名为 specularOutput。
        ➒ 这个例子用了一个远光源，离图像足够远，因而光照射到图片所有部分的角度都一样。所以这里不是指定光源的位置，而是指定光线来源的角度。
          elevation 和 azimuth 属性允许我们从三个维度指定角度。
          elevation 提供了屏幕平面上光的角度：elevation="0" 表示光线平行于整个图像，而 elevation="90" 表示光线直射下来。
          azimuth 属性在平面内指定了角度，当 elevation 为 0 时，
            azimuth="0" 指定光线从图像右侧来（更普遍的说法是 x 轴正值结束处）；
            azimuth="90" 表示从底部（y 轴正值结束处）来，
            azimuth="180" 表示从左侧来，
            azimuth="270" 表示从顶部来。
        ➓ <feSpecularLighting> 元素结束。注意，这个滤镜的输入信息是一个阿尔法通道，而输出包含阿尔法和颜色信息（不像 <feDiffuseLighting>，总是生成一个不透明的结果）。<feComposite> 的 in 属性裁剪滤镜的输出到源图形（圆）的边界。最后，用 <feComposite> 的 arithmetic 运算符将光照和源图像叠加。在圆形上启动滤镜，生成如图 11-20 所示的高亮浮雕效果。
      -->


      <!-- 访问背景 -->
      <defs>
        <filter id="blur-background"> ➊
          <feGaussianBlur in="BackgroundImage"
                          stdDeviation="4"
                          result="blur" />
          <feComposite in="blur"
                       in2="SourceGraphic"
                       operator="in" />
          <feOffset dx="4"
                    dy="4"
                    result="offsetBlur" />
        </filter>
      </defs>
      <!-- enable-background="new"，目前（2023年8月15日）没有浏览器实现，所以不生效 -->
      <g enable-background="new"> ➋
        <rect x="250"
              y="10"
              width="60"
              height="60"
              style="fill: lightblue; stroke: blue; stroke-width: 10" /> ➌
        <circle cx="290"
                cy="50"
                r="30"
                style="fill: #ffffff; filter: url(#blur-background);" /> ➍
      </g>

      <!--
        ➊ 类似用于投影的模糊滤镜，只是输入信息是 BackgroundImage 而不是 SourceAlpha。
        ➋ 由于 <g> 是一个容器元素，在这里放置 enable-background 是一个完美的选择。它所有的子元素都可以利用背景图像和阿尔法信息。
        ➌ 把矩形绘制到画布上，然后进入背景缓冲区里。
        ➍ 圆形不会直接显示；滤镜会模糊背景图像（不包括圆形），然后合成 in 属性值SourceGraphic。
      -->


      <!-- 以下方案也没有实现 -->
      <defs>
        <filter id="blur-background">
          <feImage xlink:href="#background"
                   result="bg" />
          <feGaussianBlur in="bg"
                          stdDeviation="2"
                          result="blur" />
          <feComposite in="blur"
                       in2="SourceGraphic"
                       operator="in" />
          <feOffset dx="4"
                    dy="4"
                    result="offsetBlur" />
        </filter>
      </defs>
      <g id="background">
        <rect x="330"
              y="10"
              width="60"
              height="60"
              style="fill: lightblue; stroke: blue; stroke-width: 10" />
      </g>
      <circle cx="370"
              cy="50"
              r="30"
              style="fill: #ffffff; filter: url(#blur-background);" />


    </svg>


    <script>
      const ele = document.querySelector("#xxx");
      let n = 0;
      function Renderer() {
        n++;
        if (n >= 360) n = 0;
        window.requestAnimationFrame(Renderer);
      }
      // Renderer();
    </script>
  </body>

</html>
